package com.ltv.xiangqiplugin.views;

import java.applet.Applet;
import java.applet.AppletContext;
import java.applet.AppletStub;
import java.applet.AudioClip;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import com.ltv.xiangqiplugin.models.BoardSizeEnum;
import com.ltv.xiangqiplugin.models.Game;
import com.ltv.xiangqiplugin.models.InvalidPositionException;
import com.ltv.xiangqiplugin.models.JChessFileFilter;
import com.ltv.xiangqiplugin.models.Messages;
import com.ltv.xiangqiplugin.models.MessagesObserver;
import com.ltv.xiangqiplugin.utils.MessageBox;
import com.ltv.xiangqiplugin.utils.MoveUtils;
import com.ltv.xiangqiplugin.utils.SaveLoadUtil;

/**
 *  Illustrates how a JFrame subclass can implement the
 *  AppletStub & AppletContext interfaces to build a
 *  rudimentary appletviewer.
 *
 *  Here the getDocumentBase (), getImage (URL url), and
 *  getCodeBase () were implemented in detail. You will
 *  need to implement the other methods as needed.
 **/
public class ChessAppMain extends JFrame
	implements ActionListener, AppletStub, AppletContext, MessagesObserver {
	private JMenu fileMemu;
	private JMenuItem newMenu;
	private JMenuItem newTacticMenu;
	private JMenuItem saveMenu;
	private JMenuItem loadMenu;
	private JMenuItem quitMenu;
	
	private JMenu settingsMenu;
	private JMenuItem preferencesMenu;
	
	private JMenu helpMenu;
	private JMenuItem aboutMenu;
	
	private ChessApp applet;

	/** Create a menubar for the frame and a File menu. **/
	public ChessAppMain () {
		super();
		
		Messages.getInstance().addObserver(this);
		setTitle ("CCMaker");
		fileMemu = new JMenu (Messages.getInstance().getProperty("menu.file"));
		quitMenu = new JMenuItem (Messages.getInstance().getProperty("menu.file.quit"));
		newMenu = new JMenuItem (Messages.getInstance().getProperty("menu.file.new"));
		newTacticMenu = new JMenuItem (Messages.getInstance().getProperty("menu.file.new_tactic"));
		saveMenu = new JMenuItem (Messages.getInstance().getProperty("menu.file.save"));
		loadMenu = new JMenuItem (Messages.getInstance().getProperty("menu.file.load"));
		
		settingsMenu = new JMenu (Messages.getInstance().getProperty("menu.settings"));
		preferencesMenu = new JMenuItem (Messages.getInstance().getProperty("menu.settings.preferences"));
		
		quitMenu.setActionCommand("QUIT");
		quitMenu.addActionListener (this);
		
		newMenu.setActionCommand("NEW");
		newMenu.addActionListener (this);
		
		newTacticMenu.setActionCommand("NEW_TACTIC");
		newTacticMenu.addActionListener (this);
		
		saveMenu.setActionCommand("SAVE");
		saveMenu.addActionListener (this);
		
		loadMenu.setActionCommand("LOAD");
		loadMenu.addActionListener (this);
		
		preferencesMenu.setActionCommand("OPTION");
		preferencesMenu.addActionListener (this);
		
		fileMemu.add (newMenu);
		fileMemu.add (newTacticMenu);
		fileMemu.add (saveMenu);
		fileMemu.add (loadMenu);
		fileMemu.add (quitMenu);
		
		settingsMenu.add (preferencesMenu);
		
		helpMenu = new JMenu(Messages.getInstance().getProperty("menu.help"));
		aboutMenu = new JMenuItem(Messages.getInstance().getProperty("menu.help.about") + " " + "CCMaker");
		
		helpMenu.add(aboutMenu);
		aboutMenu.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				AboutView.getInstance().showContent("CCMaker");
			}
		});
		
		JMenuBar mb = new JMenuBar ();
		mb.add (fileMemu);
		mb.add (settingsMenu);
		mb.add (helpMenu);
		
		setJMenuBar (mb);
		mb.requestFocus();
		
		// Replace "_JApplet" with the applet of interest.
		applet = new ChessApp ();
		applet.setStandaloneApp(true);
		
		applet.setStub (this);
		
		// Call init() to do whatever initialization can be
		// done outside of a browser environment.
		applet.init ();
		
		this.getContentPane().add (BorderLayout.CENTER, applet.getContentPane());
		
		// Call start();
		applet.start();
		
		this.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				if (!Messages.getInstance().storePreferences()) {
				      //JOptionPane.showMessageDialog(null, Messages.getInstance().getProperty("preferences.store.error"),
				    		  //Messages.getInstance().getProperty("error"), JOptionPane.ERROR_MESSAGE);
				      
				      MessageBox.showInformMessage(ChessAppMain.this, Messages.getInstance().getProperty("error"),
				    		  Messages.getInstance().getProperty("preferences.store.error"), JOptionPane.ERROR_MESSAGE);
				}
				System.exit(0);
			}
			
		});
		
	} // ctor
	
	// AppletStub methods

	/**
	 * Use the File class  (See lecture 9) and the System properties
	 * to create a URL from the current working directory.
	 **/
	public URL getDocumentBase () {
		URL url = null;
		try {
			File file = new File (System.getProperty ("user.dir"));
			url = file.toURL ();
		}
		catch  (MalformedURLException e) {
			System.out.println ("Bad URL");
			url = null;
		}
		return url;
	} // getDocumentBase

	/** Provide getCodeBae that returns a URL
	 * that points to the local directory where
	 * this program is running.
	 **/
	public URL getCodeBase () {
		URL url = null;
		try  {
			File file = new File (System.getProperty ("user.dir"));
			url = file.toURL ();
			System.out.println ("url="+url);
		}
		catch  (MalformedURLException e) {
			System.out.println ("Bad URL");
			url = null;
		}
		return url;

	} // getCodeBase

	// Note: ignore the warning that there is also a private isActive
	// method in the java.awt.Window class.
	public boolean isActive () { 
		return true;
	}
	
	public String getParameter (String name) {
		return "";
	}
	
	public AppletContext getAppletContext () {
		return this;
	}
	
	public void appletResize (int width, int height) {
	}

	// AppletContext methods

	// Use the toolkit to get the image from the local directory
	public Image getImage (URL url) {
		String imgName = url.getFile ();
		return Toolkit.getDefaultToolkit ().getImage (imgName);
	}

	public AudioClip getAudioClip (URL url) {
		return null;
	}
	
	public Applet getApplet (String name) {
		return null;
	}
	
	public Enumeration<Applet> getApplets () {
		return null;
	}
	
	public void showDocument (URL url) {
	}

	public void showDocument (URL url, String target) {
	}
	
	public void showStatus (String status) {
	}

	// New AppletContext methods added in vers.1.4
	public void setStream (String key, InputStream stream) {
	}

	public Iterator<String> getStreamKeys () {
		return null;
	}
	
	public InputStream getStream (String key){
		return null;
	}


	/**
	 * Create the viwer and load the applet into it.
	 **/
	public static void main (String [] args) {
		new ChessAppMain ();
	}

	public void actionPerformed (ActionEvent event) {
		String command = event.getActionCommand();
		if (command.compareTo("QUIT") == 0) {
			if (!Messages.getInstance().storePreferences()) {
			      //JOptionPane.showMessageDialog(null, Messages.getInstance().getProperty("preferences.store.error"),
			    		  //Messages.getInstance().getProperty("error"), JOptionPane.ERROR_MESSAGE);
				MessageBox.showInformMessage(ChessAppMain.this, Messages.getInstance().getProperty("error"),
			    		  Messages.getInstance().getProperty("preferences.store.error"), JOptionPane.ERROR_MESSAGE);
			}
			System.exit (0);
		}  else if (command.compareTo("NEW") == 0) {
            newGame();
        }  else if (command.compareTo("NEW_TACTIC") == 0) {
            newTacticGame();
        }  else if (command.compareTo("SAVE") == 0) {
            saveGame();
        }  else if (command.compareTo("LOAD") == 0) {
            loadGame();
        }  else if (command.compareTo("OPTION") == 0) {
            applet.getOptionView().setVisible(true);
        }
	} // actionPerformed
	
	private void newGame() {
		Game game = new Game();
		applet.getBoardView().setGame(game);
		applet.getBoardView().setColor('r');
		applet.getBoardView().setReverse(true);
		applet.getBoardView().clearHighlights();
		applet.getBoardView().clearLastMoves();
		applet.getBoardViewControl().setOriginPanel(null);
		
		applet.getPositionStack().getPositions().clear();
		applet.getMoveStack().getMoves().clear();
		applet.getMoveStack().getVnMoves().clear();
		
		applet.getPositionStack().getPositions().add(game.getPosition());
		applet.getMoveStack().getMoves().add("start");
		applet.getMoveStack().getVnMoves().add("start");
		
		applet.getPositionStack().setIndex(0);
		applet.getMoveStack().setIndex(0);
		
		applet.getPositionStack().notifyObservers();
		applet.getMoveStack().notifyObservers(true);
	}
	
	private JTextField fenInput = new JTextField();
	
	private JLabel getLabelForFENDialog() {
		return new JLabel(Messages.getInstance().getProperty("new_tactic.input_message"));
	}
	
	private JButton getButtonForFENDialog() {
        JButton button = new JButton("[" + Messages.getInstance().getProperty("new_tactic.what_is_fen") + "]");
        button.setFocusPainted(false);
        button.setMargin(new Insets(0, 0, 0, 0));
        button.setContentAreaFilled(false);
        button.setBorderPainted(false);
        button.setOpaque(false);
        button.setCursor(new Cursor(Cursor.HAND_CURSOR));
        button.setForeground(Color.BLUE);
        
        button.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				//JOptionPane.showMessageDialog(null, AboutFENView.getInstance().getLocalPanel());
				MessageBox.showInformMessage(ChessAppMain.this, "",
						AboutFENView.getInstance().getLocalPanel(), JOptionPane.INFORMATION_MESSAGE);
			}
		});
        
        return button;
	}
	
	private void newTacticGame() {
		Object[] foo = {getLabelForFENDialog(), fenInput, getButtonForFENDialog()};
		//int answerKey = JOptionPane.showOptionDialog(this, foo, "",
				//JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null,
				//new Object[] {Messages.getInstance().getProperty("button.ok"), Messages.getInstance().getProperty("button.cancel")},
				//foo[1]);
		int answerKey = MessageBox.showConfirmMessage(this, "", foo, JOptionPane.QUESTION_MESSAGE);

		if (answerKey == JOptionPane.OK_OPTION) {
			String initFen = fenInput.getText();
			if (initFen != null && !initFen.trim().equals("")) {
				// Backup in case of bad input fen
				Vector<String> bkMoves = new Vector<String>();
				for (int i = 0; i < applet.getMoveStack().getMoves().size() - 1; i++) {
					bkMoves.add(0, applet.getMoveStack().getMoves().get(i));
				}
				
				int bkIndex = applet.getMoveStack().getIndex();
				boolean bkReverseStatus = applet.getBoardView().isReverse();
				String bkInitFen = applet.getPositionStack().getPositions().get(applet.getPositionStack().getPositions().size() - 1);
				// end backup
				
				// Create new game
				Game game = new Game();
				applet.getBoardView().setGame(game);
				
				// Process standart FEN to our FEN
				initFen = SaveLoadUtil.getReversedFEN(initFen);
				
				boolean checkFen = true;
				try {
					game.setPosition(initFen);
				} catch (Exception e) {
					checkFen = false;
				}
				
				if (checkFen) {
					applet.getBoardView().clearHighlights();
					applet.getBoardView().clearLastMoves();
					applet.getBoardViewControl().setOriginPanel(null);
					
					applet.getPositionStack().getPositions().clear();
					applet.getMoveStack().getMoves().clear();
					applet.getMoveStack().getVnMoves().clear();
					
					applet.getPositionStack().getPositions().add(game.getPosition());
					applet.getMoveStack().getMoves().add("start");
					applet.getMoveStack().getVnMoves().add("start");
					
					applet.getPositionStack().setIndex(0);
					applet.getMoveStack().setIndex(0);
					
					applet.getPositionStack().notifyObservers();
					applet.getMoveStack().notifyObservers(true);
					
					applet.getBoardView().setReverse(bkReverseStatus);
				} else {
					// Rollback
					game = new Game();
					try {
						game.setPosition(bkInitFen);
					} catch (InvalidPositionException e) {
						// Should never happen
					}
					applet.getBoardView().setGame(game);
					applet.getBoardView().clearHighlights();
					applet.getBoardView().clearLastMoves();
					applet.getBoardViewControl().setOriginPanel(null);
					
					applet.getPositionStack().getPositions().clear();
					applet.getMoveStack().getMoves().clear();
					applet.getMoveStack().getVnMoves().clear();
					
					applet.getPositionStack().getPositions().add(game.getPosition());
					applet.getMoveStack().getMoves().add("start");
					applet.getMoveStack().getVnMoves().add("start");
					
					applet.getPositionStack().setIndex(0);
					applet.getMoveStack().setIndex(0);
					
					for (String move : bkMoves) {
						String vnMove = MoveUtils.getVnMove(move, game);
						game.move(move, false);
						
						applet.getMoveStack().getMoves().add(0, move);
						applet.getMoveStack().getVnMoves().add(0, vnMove);
						applet.getPositionStack().getPositions().add(0, game.getPosition());
					}
					
					applet.getMoveStack().setIndex(bkIndex);
					applet.getPositionStack().setIndex(bkIndex);
					
					applet.getMoveStack().notifyObservers(true);
					applet.getPositionStack().notifyObservers();
					applet.getBoardView().setReverse(bkReverseStatus);
					
					//JOptionPane.showMessageDialog(this,
							//Messages.getInstance().getProperty("new_tactic.error_message"),
							//Messages.getInstance().getProperty("error"),
							//JOptionPane.ERROR_MESSAGE);
					MessageBox.showInformMessage(this, Messages.getInstance().getProperty("error"),
							Messages.getInstance().getProperty("new_tactic.error_message"),
							JOptionPane.ERROR_MESSAGE);
				}
			}
		}
	}
	
	private void saveGame() {
		if (applet.getMoveStack().getMoves().size() > 1) {
			Vector<String> moves = new Vector<String>();
			for (int i = 0; i < applet.getMoveStack().getMoves().size() - 1; i++) {
				moves.add(applet.getMoveStack().getMoves().get(i));
			}
			
			String fen = applet.getPositionStack().getPositions().get(applet.getPositionStack().getPositions().size() - 1);
			String fields[] = fen.split(" ");
			fen = fields[0].substring(0, fields[0].length() - 1) + " " + fields[1];
			
			String initFEN = SaveLoadUtil.getReversedFEN(fen);
			
			String content = SaveLoadUtil.savePGN("", "", "", "", "", "", "",
					initFEN,
					moves);
			
			
	        int returnVal = SaveLoadFileDialog.getInstance().showSaveDialog(this);
	        
	        if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = SaveLoadFileDialog.getInstance().getSelectedFile();
                
                // Check file exists
                if (file.exists()) {
	                //int answer = JOptionPane.showConfirmDialog(this,
	                        //Messages.getInstance().getProperty("warning.file.exist"),
	                        //Messages.getInstance().getProperty("warning"),
	                        //JOptionPane.YES_NO_OPTION);
                	int answer = MessageBox.showConfirmMessage(this, Messages.getInstance().getProperty("warning"),
                			Messages.getInstance().getProperty("warning.file.exist"),
                			JOptionPane.WARNING_MESSAGE);
	                if (answer == JOptionPane.CANCEL_OPTION) {
	                	return;
	                }
                }
                //This is where a real application would save the file.
                try {
                	String fileFullName = file.getAbsolutePath();
                	
                	if (SaveLoadFileDialog.getInstance().getFileType().equals(JChessFileFilter.FILE_TYPE_PGN)) {
                		if (!fileFullName.endsWith(JChessFileFilter.FILE_TYPE_PGN)) {
                			fileFullName += JChessFileFilter.FILE_TYPE_PGN;
                		}
                	}
                	
					FileOutputStream fos = new FileOutputStream(fileFullName);
					fos.write(content.getBytes());
					fos.close();
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
            } else {
            	// Do nothing
            }
		}
	}
	
	private void loadGame() {
		int returnVal = SaveLoadFileDialog.getInstance().showOpenDialog(this);
		
		if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = SaveLoadFileDialog.getInstance().getSelectedFile();
            
			try {
				String initFEN = SaveLoadUtil.getInitFen(file);
				initFEN = SaveLoadUtil.getReversedFEN(initFEN);
				if (file.getName().toLowerCase().endsWith(JChessFileFilter.FILE_TYPE_PGN)) {
					Vector<String> allMoves = SaveLoadUtil.loadPGN(file);
					loadMove(allMoves, initFEN);
				} else {
					Vector<String> allMoves = SaveLoadUtil.loadAll(file);
					loadMove(allMoves, initFEN);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	private void loadMove(Vector<String> moves, String initPosition) {
		if (moves.size() > 0) {
			Vector<String> bkMoves = new Vector<String>();
			for (int i = 0; i < applet.getMoveStack().getMoves().size() - 1; i++) {
				bkMoves.add(0, applet.getMoveStack().getMoves().get(i));
			}
			
			int bkIndex = applet.getMoveStack().getIndex();
			boolean bkReverseStatus = applet.getBoardView().isReverse();
			String bkInitFen = applet.getPositionStack().getPositions().get(applet.getPositionStack().getPositions().size() - 1);
			
			
			// Create new game
			boolean checkFile = true;
			Game game = new Game();
			applet.getBoardView().setGame(game);
			if (!initPosition.equals("")) {
				try {
					game.setPosition(initPosition);
				} catch (Exception e) {
					checkFile = false;
				}
			}

			if (checkFile) {
				applet.getBoardView().clearHighlights();
				applet.getBoardView().clearLastMoves();
				applet.getBoardViewControl().setOriginPanel(null);
				
				applet.getPositionStack().getPositions().clear();
				applet.getMoveStack().getMoves().clear();
				applet.getMoveStack().getVnMoves().clear();
				
				applet.getPositionStack().getPositions().add(game.getPosition());
				applet.getMoveStack().getMoves().add("start");
				applet.getMoveStack().getVnMoves().add("start");
				
				applet.getPositionStack().setIndex(0);
				applet.getMoveStack().setIndex(0);
				
				applet.getPositionStack().notifyObservers();
				applet.getMoveStack().notifyObservers(true);
				
				for (String move : moves) {
					String vnMove = MoveUtils.getVnMove(move, game);
					
					if (!game.move(move, false)) {
						checkFile = false;
						break;
					}
					
					applet.getMoveStack().getMoves().add(0, move);
					applet.getMoveStack().getVnMoves().add(0, vnMove);
					applet.getPositionStack().getPositions().add(0, game.getPosition());
				}
			}
			
			if (checkFile) {
				applet.getMoveStack().notifyObservers(true);
				applet.getPositionStack().notifyObservers();
				applet.getBoardView().setReverse(bkReverseStatus);
			} else {
				game = new Game();
				try {
					game.setPosition(bkInitFen);
				} catch (InvalidPositionException e) {
					// Should never happen
				}
				applet.getBoardView().setGame(game);
				applet.getBoardView().clearHighlights();
				applet.getBoardView().clearLastMoves();
				applet.getBoardViewControl().setOriginPanel(null);
				
				applet.getPositionStack().getPositions().clear();
				applet.getMoveStack().getMoves().clear();
				applet.getMoveStack().getVnMoves().clear();
				
				applet.getPositionStack().getPositions().add(game.getPosition());
				applet.getMoveStack().getMoves().add("start");
				applet.getMoveStack().getVnMoves().add("start");
				
				applet.getPositionStack().setIndex(0);
				applet.getMoveStack().setIndex(0);
				
				for (String move : bkMoves) {
					String vnMove = MoveUtils.getVnMove(move, game);
					game.move(move, false);
					
					applet.getMoveStack().getMoves().add(0, move);
					applet.getMoveStack().getVnMoves().add(0, vnMove);
					applet.getPositionStack().getPositions().add(0, game.getPosition());
				}
				
				applet.getMoveStack().setIndex(bkIndex);
				applet.getPositionStack().setIndex(bkIndex);
				
				applet.getMoveStack().notifyObservers(true);
				applet.getPositionStack().notifyObservers();
				applet.getBoardView().setReverse(bkReverseStatus);
				
				//JOptionPane.showMessageDialog(this,
						//Messages.getInstance().getProperty("load.error"),
						//Messages.getInstance().getProperty("error"),
						//JOptionPane.ERROR_MESSAGE);
				MessageBox.showInformMessage(this, Messages.getInstance().getProperty("error"),
						Messages.getInstance().getProperty("load.error"),
						JOptionPane.ERROR_MESSAGE);
			}
			
		} else {
			//JOptionPane.showMessageDialog(this,
					//Messages.getInstance().getProperty("load.error"),
					//Messages.getInstance().getProperty("error"),
					//JOptionPane.ERROR_MESSAGE);
			MessageBox.showInformMessage(this, Messages.getInstance().getProperty("error"),
					Messages.getInstance().getProperty("load.error"),
					JOptionPane.ERROR_MESSAGE);
		}
	}

	@Override
	public void messagesChanged() {
		fileMemu.setText(Messages.getInstance().getProperty("menu.file"));
		quitMenu.setText(Messages.getInstance().getProperty("menu.file.quit"));
		newMenu.setText(Messages.getInstance().getProperty("menu.file.new"));
		newTacticMenu.setText(Messages.getInstance().getProperty("menu.file.new_tactic"));
		saveMenu.setText(Messages.getInstance().getProperty("menu.file.save"));
		loadMenu.setText(Messages.getInstance().getProperty("menu.file.load"));
		
		settingsMenu.setText(Messages.getInstance().getProperty("menu.settings"));
		preferencesMenu.setText(Messages.getInstance().getProperty("menu.settings.preferences"));
		
		helpMenu.setText(Messages.getInstance().getProperty("menu.help"));
		aboutMenu.setText(Messages.getInstance().getProperty("menu.help.about") + " " + "CCMaker");
		
		BoardSizeEnum boardSize = Messages.getInstance().getBoardSize();
		
		if (boardSize == BoardSizeEnum.SMALL) {
			setSize(400, 380);
		} else if (boardSize == BoardSizeEnum.MEDIUM) {
			setSize(550, 530);
		} else if (boardSize == BoardSizeEnum.LARGE) {
			setSize(700, 680);
		} else {
			setSize(550, 530);
		}
		centerScreen();
		setVisible (true);
	}
	
	private void centerScreen() {
		int x = (Toolkit.getDefaultToolkit().getScreenSize().width - getWidth())/2;
		int y = (Toolkit.getDefaultToolkit().getScreenSize().height - getHeight())/2;
		
		setLocation(x, y);
	}

} // class StartJAppletViewer 